{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions)\n",
    "When something goes wrong an exception is raised. For example, if you try to divide by zero, `ZeroDivisionError` is raised or if you try to access a nonexistent key in a dictionary, `KeyError` is raised.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "empty_dict = {}\n",
    "# empty_dict['key']  # Uncomment to see the traceback"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `try-except` structure \n",
    "If you know that a block of code can fail in some manner, you can use `try-except` structure to handle potential exceptions in a desired way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's try to open a file that does not exist\n",
    "file_name = 'not_existing.txt'\n",
    "\n",
    "try:\n",
    "    with open(file_name, 'r') as my_file:\n",
    "        print('File is successfully open')\n",
    "        \n",
    "except FileNotFoundError as e:\n",
    "    print('Uups, file: {} not found'.format(file_name))\n",
    "    print('Exception: {} was raised'.format(e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you don't know the type of exceptions that a code block can possibly raise, you can use `Exception` which catches all exceptions. In addition, you can have multiple `except` statements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_division(var1, var2):\n",
    "    result = 0\n",
    "    \n",
    "    try:\n",
    "        result = var1 / var2\n",
    "    except ZeroDivisionError as ex1:\n",
    "        print(\"Can't divide by zero\")\n",
    "    except Exception as ex2:\n",
    "        print('Exception: {}'.format(ex2))\n",
    "\n",
    "    return result\n",
    "\n",
    "result1 = calculate_division(3, 3)\n",
    "print('result1: {}'.format(result1))\n",
    "\n",
    "result2 = calculate_division(3, '3')\n",
    "print('result2: {}'.format(result2))\n",
    "\n",
    "result3 = calculate_division(3, 0)\n",
    "print('result3: {}'.format(result3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`try-except` can be also in outer scope:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_division(var1, var2):\n",
    "    return var1 / var2\n",
    "\n",
    "try:\n",
    "    result = calculate_division(3, '3')\n",
    "except Exception as e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating your custom exceptions\n",
    "In your own applications, you can use custom exceptions for signaling users about errors which occur during your application run time.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "# Define your own exception\n",
    "class NegativeNumbersNotSupported(Exception):\n",
    "    pass\n",
    "\n",
    "# Dummy example how to use your custom exception\n",
    "def secret_calculation(number1, number2):\n",
    "    if number1 < 0 or number2 < 0:\n",
    "        msg = 'Negative number in at least one of the parameters: {}, {}'.format(\n",
    "            number1, number2)\n",
    "        raise NegativeNumbersNotSupported(msg)\n",
    "\n",
    "    return math.sqrt(number1) + math.sqrt(number2)\n",
    "\n",
    "# Uncomment to see the traceback\n",
    "# result = secret_calculation(-1, 1)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3.0
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}